package ci.web.codec;

import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpUtil;
import io.netty.util.AttributeKey;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;

import java.io.IOException;
import java.util.concurrent.atomic.AtomicInteger;

import ci.web.core.CiContext;

/**
 * http-channel-data-handler
 * @author zhh
 */
@ChannelHandler.Sharable
public abstract class CiHttpHandler extends SimpleChannelInboundHandler<Object> {

    private static final InternalLogger logger = InternalLoggerFactory.getInstance(CiHttpHandler.class);
    
    private AtomicInteger counter;
    private int limit;
    private volatile boolean enable = true;
    public CiHttpHandler() {
        this(0);
    }
    public CiHttpHandler(int limit) {
        counter = new AtomicInteger();
        this.limit = limit;
    }
    /**
     * 停用
     */
    public void disable() {
        enable = false;
    }
    
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object msg)
            throws Exception {
        if ((msg instanceof FullHttpRequest)){
            FullHttpRequest req = (FullHttpRequest) msg;
            if (!req.decoderResult().isSuccess()) {
                DefaultFullHttpResponse ret = new DefaultFullHttpResponse(req.protocolVersion(), HttpResponseStatus.INTERNAL_SERVER_ERROR);
                HttpUtil.setKeepAlive(ret, false);
                ctx.writeAndFlush(ret).addListener(ChannelFutureListener.CLOSE);
                return;
            }
            CiContext context = new CiContext(ctx, req);
            if(doProcess(context)==false){
                context.out().setStatus(HttpResponseStatus.NOT_FOUND);
            }
            if(context.isFinish()==false){
                if(context.isDelay()==false){
                    context.finish();
                }
            }
        }
    }
    
    protected abstract boolean doProcess(CiContext context) throws Exception;
    
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
            throws Exception {
        if((cause instanceof IOException)==false){
            logger.error("", cause);
        }
        ctx.channel().close();
    }
    
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        if(enable==false || (limit>0 && counter.get()>limit)){
            ctx.close();
            return;
        }
        super.channelActive(ctx);
        ctx.attr(COUNTER_KEY).set(COUNTER_FLAG);
        counter.incrementAndGet();
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        Object f = ctx.attr(COUNTER_KEY).getAndRemove();
        if(f!=null){
            counter.decrementAndGet();
        }
        super.channelInactive(ctx);
    }

    /**
     * 当前保持的-http-连接数（不等于工作中的数量）
     * @return
     */
    public int connectNum(){
        return counter.get();
    }
    private static Byte COUNTER_FLAG = 1;
    private static final AttributeKey<Object> COUNTER_KEY = AttributeKey.valueOf("COUNTER_KEY");
    

}
